package com.weifly.weistock.module.stockbill.impl;

import com.weifly.weistock.bo.record.RecordPairBO;
import com.weifly.weistock.core.common.StockException;
import com.weifly.weistock.core.config.AbstractConfigService;
import com.weifly.weistock.core.config.ConfigConstants;
import com.weifly.weistock.core.constant.StockBillBusinessNameEnum;
import com.weifly.weistock.core.util.RecordUtils;
import com.weifly.weistock.module.stockbill.StockBillConverter;
import com.weifly.weistock.module.stockbill.StockBillStoreService;
import com.weifly.weistock.module.stockbill.bo.StockRecordBO;
import com.weifly.weistock.module.stockbill.bo.StockSummaryBO;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentFactory;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

/**
 * 股票交易记录存储服务
 *
 * @author weifly
 * @since 2020/01/16
 */
public class StockBillStoreServiceImpl extends AbstractConfigService implements StockBillStoreService {

    private static final String ATTR_DATE = "date";
    private static final String ATTR_TIME = "time";
    private static final String ATTR_BUSINESS_NAME = "businessName";
    private static final String ATTR_TRADE_PRICE = "tradePrice";
    private static final String ATTR_TRADE_NUMBER = "tradeNumber";
    private static final String ATTR_TRADE_AMOUNT = "tradeAmount";
    private static final String ATTR_AFTER_NUMBER = "afterNumber";
    private static final String ATTR_FEE_SERVICE = "feeService";
    private static final String ATTR_FEE_STAMP = "feeStamp";
    private static final String ATTR_FEE_TRANSFER = "feeTransfer";
    private static final String ATTR_FEE_EXTRA = "feeExtra";
    private static final String ATTR_FEE_CLEAR = "feeClear";
    private static final String ATTR_CLEAR_AMOUNT = "clearAmount";
    private static final String ATTR_AFTER_AMOUNT = "afterAmount";
    private static final String ATTR_ENTRUST_CODE = "entrustCode";
    private static final String ATTR_PAIR = "pair";
    private static final String ATTR_DIFF_AMOUNT = "diffAmount";

    @Override
    public List<StockSummaryBO> loadStockList() {
        List<StockSummaryBO> stockList = new ArrayList<>();
        for (File xmlFile : this.getConfigFolder().listFiles()) {
            if (xmlFile.getName().endsWith(".xml")) {
                log.info("加载股票账单记录：" + xmlFile.getAbsolutePath());
                StockSummaryBO summaryDto = this.loadXmlFile(xmlFile);
                stockList.add(summaryDto);
            }
        }
        return stockList;
    }

    @Override
    public StockSummaryBO loadStockSummary(String stockCode) {
        String xmlFileName = "bill_" + stockCode + ".xml";
        File xmlFile = new File(this.getConfigFolder(), xmlFileName);
        if (!xmlFile.exists()) {
            log.info("文件不存在：" + xmlFile.getAbsolutePath());
            return null;
        }
        log.info("加载股票记录：" + xmlFile.getAbsolutePath());
        return this.loadXmlFile(xmlFile);
    }

    private StockSummaryBO loadXmlFile(File xmlFile) {
        StockSummaryBO summaryBO = new StockSummaryBO();
        try {
            SAXReader reader = new SAXReader();
            Document document = reader.read(xmlFile);
            Element rootEle = document.getRootElement();

            String stockCode = rootEle.attributeValue(ConfigConstants.ATTR_STOCK_CODE);
            summaryBO.setStockCode(stockCode);
            String stockName = rootEle.attributeValue(ConfigConstants.ATTR_STOCK_NAME);
            summaryBO.setStockName(stockName);
            String summaryDiffAmount = rootEle.attributeValue(ATTR_DIFF_AMOUNT);
            if (StringUtils.isNotBlank(summaryDiffAmount)) {
                summaryBO.setDiffAmount(Double.valueOf(summaryDiffAmount));
            }
            String summaryFeeService = rootEle.attributeValue(ATTR_FEE_SERVICE);
            if (StringUtils.isNotBlank(summaryFeeService)) {
                summaryBO.setFeeService(Double.valueOf(summaryFeeService));
            }
            String summaryFeeStamp = rootEle.attributeValue(ATTR_FEE_STAMP);
            if (StringUtils.isNotBlank(summaryFeeStamp)) {
                summaryBO.setFeeStamp(Double.valueOf(summaryFeeStamp));
            }
            String summaryAfterNumber = rootEle.attributeValue(ATTR_AFTER_NUMBER);
            if (StringUtils.isNotBlank(summaryAfterNumber)) {
                summaryBO.setAfterNumber(Integer.valueOf(summaryAfterNumber));
            }

            List<Element> recordEleList = rootEle.elements(ConfigConstants.ELE_RECORD);
            if (recordEleList != null) {
                for (Element recordEle : recordEleList) {
                    StockRecordBO recordBO = new StockRecordBO();
                    // 发生日期
                    recordBO.setDate(recordEle.attributeValue(ATTR_DATE));
                    // 成交时间
                    recordBO.setTime(recordEle.attributeValue(ATTR_TIME));
                    // 业务名称
                    String businessNameValue = recordEle.attributeValue(ATTR_BUSINESS_NAME);
                    StockBillBusinessNameEnum businessNameEnum = StockBillBusinessNameEnum.getEnumByName(businessNameValue);
                    if (businessNameEnum == null) {
                        throw new StockException("不支持的businessName: " + businessNameValue);
                    }
                    recordBO.setBusinessName(businessNameEnum);
                    // 证券代码
                    recordBO.setStockCode(recordEle.attributeValue(ConfigConstants.ATTR_STOCK_CODE));
                    // 证券名称
                    recordBO.setStockName(recordEle.attributeValue(ConfigConstants.ATTR_STOCK_NAME));
                    // 成交价格
                    recordBO.setTradePrice(Double.valueOf(recordEle.attributeValue(ATTR_TRADE_PRICE)));
                    // 成交数量
                    recordBO.setTradeNumber(Integer.valueOf(recordEle.attributeValue(ATTR_TRADE_NUMBER)));
                    // 成交金额
                    String tradeAmount = recordEle.attributeValue(ATTR_TRADE_AMOUNT);
                    if (StringUtils.isNotBlank(tradeAmount)) {
                        recordBO.setTradeAmount(Double.valueOf(tradeAmount));
                    }
                    // 股份余额
                    String afterNumber = recordEle.attributeValue(ATTR_AFTER_NUMBER);
                    if (StringUtils.isNotBlank(afterNumber)) {
                        recordBO.setAfterNumber(Integer.valueOf(afterNumber));
                    }
                    // 手续费
                    recordBO.setFeeService(Double.valueOf(recordEle.attributeValue(ATTR_FEE_SERVICE)));
                    // 印花税
                    recordBO.setFeeStamp(Double.valueOf(recordEle.attributeValue(ATTR_FEE_STAMP)));
                    // 过户费
                    recordBO.setFeeTransfer(Double.valueOf(recordEle.attributeValue(ATTR_FEE_TRANSFER)));
                    // 附加费
                    String feeExtra = recordEle.attributeValue(ATTR_FEE_EXTRA);
                    if (StringUtils.isNotBlank(feeExtra)) {
                        recordBO.setFeeExtra(Double.valueOf(feeExtra));
                    }
                    // 交易所清算费
                    recordBO.setFeeClear(Double.valueOf(recordEle.attributeValue(ATTR_FEE_CLEAR)));
                    // 发生金额
                    recordBO.setClearAmount(Double.valueOf(recordEle.attributeValue(ATTR_CLEAR_AMOUNT)));
                    // 资金本次余额
                    recordBO.setAfterAmount(Double.valueOf(recordEle.attributeValue(ATTR_AFTER_AMOUNT)));
                    // 委托编号
                    recordBO.setEntrustCode(recordEle.attributeValue(ATTR_ENTRUST_CODE));

                    // 配对信息
                    List<RecordPairBO> pairList = RecordUtils.parsePairAttr(recordEle.attributeValue(ATTR_PAIR), recordBO.getTradeNumber());
                    if (pairList != null) {
                        recordBO.setPairList(pairList);
                    }
                    // 配对结算金额
                    String diffAmountValue = recordEle.attributeValue(ATTR_DIFF_AMOUNT);
                    if (StringUtils.isNotBlank(diffAmountValue)) {
                        recordBO.setDiffAmount(Double.valueOf(diffAmountValue));
                    }

                    StockBillConverter.addRecordToSummary(summaryBO, recordBO, null);
                }
            }
            return summaryBO;
        } catch (DocumentException e) {
            log.error("", e);
            throw new RuntimeException(e);
        }
    }

    @Override
    public void saveStockSummary(StockSummaryBO summaryBO) {
        DocumentFactory factory = DocumentFactory.getInstance();

        Document document = factory.createDocument();
        document.setXMLEncoding("UTF8");

        Element rootEle = factory.createElement(ConfigConstants.ELE_ROOT);
        rootEle.addAttribute(ConfigConstants.ATTR_STOCK_CODE, summaryBO.getStockCode());
        rootEle.addAttribute(ConfigConstants.ATTR_STOCK_NAME, summaryBO.getStockName());
        if (summaryBO.getDiffAmount() != null) {
            rootEle.addAttribute(ATTR_DIFF_AMOUNT, summaryBO.getDiffAmount().toString());
        }
        if (summaryBO.getFeeService() != null) {
            rootEle.addAttribute(ATTR_FEE_SERVICE, summaryBO.getFeeService().toString());
        }
        if (summaryBO.getFeeStamp() != null) {
            rootEle.addAttribute(ATTR_FEE_STAMP, summaryBO.getFeeStamp().toString());
        }
        if (summaryBO.getAfterNumber() != null) {
            rootEle.addAttribute(ATTR_AFTER_NUMBER, summaryBO.getAfterNumber().toString());
        }
        document.setRootElement(rootEle);

        for (StockRecordBO recordBO : summaryBO.getRecordList()) {
            Element recordEle = factory.createElement(ConfigConstants.ELE_RECORD);
            recordEle.addAttribute(ATTR_DATE, recordBO.getDate());
            recordEle.addAttribute(ATTR_TIME, recordBO.getTime());
            recordEle.addAttribute(ATTR_BUSINESS_NAME, recordBO.getBusinessName().getName());
            recordEle.addAttribute(ConfigConstants.ATTR_STOCK_NAME, recordBO.getStockName());
            recordEle.addAttribute(ConfigConstants.ATTR_STOCK_CODE, recordBO.getStockCode());
            recordEle.addAttribute(ATTR_TRADE_PRICE, recordBO.getTradePrice().toString());
            recordEle.addAttribute(ATTR_TRADE_NUMBER, recordBO.getTradeNumber().toString());
            if (recordBO.getTradeAmount() != null) {
                recordEle.addAttribute(ATTR_TRADE_AMOUNT, recordBO.getTradeAmount().toString());
            }
            if (recordBO.getAfterNumber() != null) {
                recordEle.addAttribute(ATTR_AFTER_NUMBER, recordBO.getAfterNumber().toString());
            }
            recordEle.addAttribute(ATTR_FEE_SERVICE, recordBO.getFeeService().toString());
            recordEle.addAttribute(ATTR_FEE_STAMP, recordBO.getFeeStamp().toString());
            recordEle.addAttribute(ATTR_FEE_TRANSFER, recordBO.getFeeTransfer().toString());
            if (recordBO.getFeeExtra() != null) {
                recordEle.addAttribute(ATTR_FEE_EXTRA, recordBO.getFeeExtra().toString());
            }
            recordEle.addAttribute(ATTR_FEE_CLEAR, recordBO.getFeeClear().toString());
            recordEle.addAttribute(ATTR_CLEAR_AMOUNT, recordBO.getClearAmount().toString());
            recordEle.addAttribute(ATTR_AFTER_AMOUNT, recordBO.getAfterAmount().toString());
            recordEle.addAttribute(ATTR_ENTRUST_CODE, recordBO.getEntrustCode());

            String pairAttr = RecordUtils.makePairAttr(recordBO.getPairList(), recordBO.getTradeNumber());
            if (pairAttr != null) {
                recordEle.addAttribute(ATTR_PAIR, pairAttr);
            }
            if (recordBO.getDiffAmount() != null) {
                recordEle.addAttribute(ATTR_DIFF_AMOUNT, recordBO.getDiffAmount().toString());
            }
            rootEle.add(recordEle);
        }

        String xmlFileName = "bill_" + summaryBO.getStockCode() + ".xml";
        File xmlFile = new File(this.getConfigFolder(), xmlFileName);
        log.info("保存股票交易记录, file={}", xmlFile.getAbsolutePath());
        this.saveConfig(xmlFile, document);
    }
}
